package service

import (
	"context"
	"errors"
	"fmt"
	accoutv1 "jk-time/webook/api/proto/gen/account/v1"
	paymentv1 "jk-time/webook/api/proto/gen/payment/v1"
	"jk-time/webook/pkg/logger"
	"jk-time/webook/reward/domain"
	"jk-time/webook/reward/repository"
	"strconv"
	"strings"
)

type WechatRewardService struct {
	client        paymentv1.PaymentSerivceClient
	accountClient accoutv1.AccountSerivceClient
	repo          repository.RewardRepository
	l             logger.Logger
}

func NewWechatRewardService(client paymentv1.PaymentSerivceClient, repo repository.RewardRepository, l logger.Logger) RewardService {
	return &WechatRewardService{client: client, repo: repo, l: l}
}

func (w WechatRewardService) PreReward(ctx context.Context, reward domain.Reward) (domain.CodeURL, error) {
	// 查询缓存，是不是已经创建过了打赏的预支付订单
	cu, err := w.repo.GetCachedCodeURL(ctx, reward)
	if err == nil {
		return cu, nil
	}

	reward.Status = domain.RewardStatusInit
	rid, err := w.repo.CreateReward(ctx, reward)
	if err != nil {
		return domain.CodeURL{}, nil
	}

	pmtResp, err := w.client.NativePrepay(ctx, &paymentv1.PrepayRequest{
		Amt: &paymentv1.Amount{
			Total:    reward.Amt,
			Currency: "CNY",
		},
		BizTradeNo:  w.bizTradeNO(rid),
		Description: fmt.Sprintf("打赏-%s", reward.BizName),
	})
	if err != nil {
		w.l.Error("生成二维码失败",
			logger.Error(err),
			logger.Int64("rid", rid))
		return domain.CodeURL{}, nil
	}

	cu = domain.CodeURL{Rid: rid, URL: pmtResp.CodeUrl}
	go func() {
		err = w.repo.SetCachedCodeURL(ctx, cu, reward)
		if err != nil {
			w.l.Error("缓存二维码失败",
				logger.Error(err),
				logger.Int64("rid", rid))
		}
	}()
	return cu, nil
}
func (w WechatRewardService) UpdateReward(ctx context.Context, bizTradeNO string, status domain.RewardStatus) error {
	rewardId := w.toRid(bizTradeNO)
	err := w.repo.UpdateReward(ctx, rewardId, status)
	if err != nil {
		return err
	}
	// 完成了支付，准备入账
	if status == domain.RewardStatusPayed {
		r, err := w.repo.GetReward(ctx, rewardId)
		if err != nil {
			return err
		}
		// webook 抽成
		weAmt := int64(float64(r.Amt) * 0.1)
		_, err = w.accountClient.Credit(ctx, &accoutv1.CreditRequest{
			Biz:   "reward",
			BizId: rewardId, //打赏的单次id，不能是作品的id，不然重复会索引失效
			Items: []*accoutv1.CredItem{
				{
					AccoutType: accoutv1.AccountType_AccountTypeSystem,
					Amt:        weAmt, //平台抽取
					Currency:   "CNY",
				},
				{
					Account:    r.Uid,
					Uid:        r.Uid,
					AccoutType: accoutv1.AccountType_AccountTypeSelf,
					Amt:        r.Amt - weAmt, //个人所有
					Currency:   "CNY",
				},
			},
		})
		if err != nil {
			w.l.Error("入账失败", logger.String("biz_trade_no", bizTradeNO), logger.Error(err))
			return err
		}
	}
	return nil
}
func (w WechatRewardService) GetReward(ctx context.Context, rid, uid int64) (domain.Reward, error) {
	res, err := w.repo.GetReward(ctx, rid)
	if err != nil {
		return domain.Reward{}, err
	}
	// 确保是自己打赏
	if res.Uid != uid {
		return domain.Reward{}, errors.New("非法访问别人的打赏记录")
	}
	// 降级或者限流的时候，不走慢路径
	if ctx.Value("limited") == "true" {
		return res, nil
	}
	// 慢路径
	if !res.Completed() {
		// 我去问一下，有可能支付那边已经处理好了，已经收到回调了
		rep, err := w.client.GetPayment(ctx, &paymentv1.GetPaymentRequest{
			BizTradeNo: w.bizTradeNO(rid),
		})
		if err != nil {
			w.l.Error("慢路径查询支付状态失败",
				logger.Error(err),
				logger.Int64("rid", rid))
			return res, nil
		}
		switch rep.GetStatus() {
		case paymentv1.PaymentStatus_PaymentStatusFailed:
			res.Status = domain.RewardStatusFailed
		case paymentv1.PaymentStatus_PaymentStatusSuccess:
			res.Status = domain.RewardStatusPayed
		case paymentv1.PaymentStatus_PaymentStatusInit:
			res.Status = domain.RewardStatusInit
		}
		err = w.UpdateReward(ctx, w.bizTradeNO(rid), res.Status)
		if err != nil {
			w.l.Error("慢路径更新本地状态失败", logger.Error(err),
				logger.Int64("rid", rid))
		}
	}
	return res, nil
}
func (w WechatRewardService) bizTradeNO(rid int64) string {
	return fmt.Sprintf("reward-%d", rid)
}
func (w WechatRewardService) toRid(bizTradeNO string) int64 {
	ridStr := strings.Split(bizTradeNO, "-")
	rid, _ := strconv.ParseInt(ridStr[1], 10, 64)
	return rid
}
